#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>
#include <stack>
class Editor
{
public:
    std::string text;
private:
    int selected = -1;
public:
    Editor()
    {
        text = "0123456789";
    }
    char getSelection()
    {
        return text.at(selected);
    }
    void select(int idx)
    {
        selected = idx;
    }
    void replaceSelection(char c)
    {
        text[selected] = c;
    }
    void printInfo()
    {
        std::cout<<text<<std::endl;
    }
};
class Application;
class Command
{
protected:
    Application *app;
    Editor *editor;
    std::string backup;
public:
    Command(Application* app_, Editor* editor_)
    {
        app = app_;
        editor = editor_;
    }
    void saveBackup()
    {
        backup = editor->text;
        //std::cout<<"Save text to backup : "<<backup<<std::endl;
    }
    virtual void undo() = 0;
    virtual bool execute() = 0;
};
class CopyCommand;
class UndoCommand;
class CutCommand;
class PasteCommand;

class CommandHistory
{
private:
    std::stack<Command*> history;
public:
    void push(Command* command)
    {
        history.push(command);
    }
    Command* pop()
    {
        Command* p = history.top();
        history.pop();
        return p;
    }
};

class Application
{
public:
    char clipboard;
private:
    CommandHistory history;
    Editor* editor;
public:
    Application()
    {
        editor = new Editor();
    }
    void select(int idx)
    {
        editor->select(idx);
    }
    void paste();
    void copy();
    void cut();
    void executeCommand(Command* p)
    {
        if(p->execute())
        {
            //std::cout<<"push command"<<std::endl;
            history.push(p);
        }
    }
    void undo()
    {
        //std::cout<<"application undo"<<std::endl;
        Command *p = history.pop();
        if( p != nullptr )
        {
            p->undo();
        }else{

        }
    }
    void printInfo()
    {
        editor->printInfo();
    };
};

class CopyCommand : public Command
{
public:
    CopyCommand(Application* app_, Editor* editor_):Command(app_,editor_){}
    bool execute() override
    {
        std::cout<<"copy command"<<std::endl;
        app->clipboard = editor->getSelection();
        return false;
    }
    void undo()override
    {

    }
};

class CutCommand : public Command
{
public:
    CutCommand(Application* app_, Editor* editor_):Command(app_,editor_){}
    bool execute() override
    {
        saveBackup();
        app->clipboard = editor->getSelection();
        editor->replaceSelection('X');
        std::cout<<"cut command"<<std::endl;
        return true;
    }
    void undo()override
    {
        editor->text = backup;
        std::cout<<"cut undo"<<std::endl;
    }
};

class PasteCommand : public Command
{
public:
    PasteCommand(Application* app_, Editor* editor_):Command(app_,editor_){}
    bool execute() override
    {
        std::cout<<"paste command begin"<<std::endl;
        saveBackup();
        editor->replaceSelection(app->clipboard);
        std::cout<<"paste command"<<std::endl;
        return true;
    }
    void undo()override
    {
        editor->text = backup;
        std::cout<<"paste undo"<<std::endl;
    }
};

class UndoCommand : public Command
{
public:
    UndoCommand(Application* app_, Editor* editor_):Command(app_,editor_){}
    bool execute() override
    {
        std::cout<<"undo command"<<std::endl;
        return false;
    }
    void undo()override
    {
    }
};
void Application::paste()
{
    executeCommand(new PasteCommand(this, editor));
}
void Application::copy()
{
    executeCommand(new CopyCommand(this, editor));
}
void Application::cut()
{
    executeCommand(new CutCommand(this, editor));
}
int main() {
    Application app;
    app.printInfo();
    app.select(0);
    app.cut();
    app.printInfo();
    app.select(9);
    app.paste();
    app.printInfo();
    app.undo();
    app.printInfo();
    app.undo();
    app.printInfo();
    return 0;
}